package com.dragonwu.utils;

import com.dragonwu.model.OnlineUser;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * 通过RSA非对称加密的JWT工具类
 *
 * @author DragonWu
 * @date 2022-10-06 17:51
 **/
public class JwtUtil {

    //默认60分钟
    public static final Long DEFAULT_EXPIRE_MINUTES = 60L;

    //jwt的唯一标识，一般为username或userId
    public static final String JWT_PRIMARY_KEY = "userId";

    //私钥路径
    public static final String PRIVATE_KEY_PATH = "/keys/dragonwu.jks";
    //公钥路径
    public static final String PUBLIC_KEY_PATH = "/keys/public.key";

    //私钥
    public static PrivateKey privateKey;
    //公钥
    public static PublicKey publicKey;

    /**
     * 传入的数据不得含敏感信息，否则可能被盗用，私钥加密token
     *
     * @param claims  数据体
     * @param minutes 过期时间，分
     * @return String   JWT的token
     */
    public static String createJwt(Map<String, Object> claims, long minutes) {
        //获取私钥
        if (Objects.isNull(privateKey)) {
            privateKey = getPrivateKey();
        }

        //当前系统时间
        long now = System.currentTimeMillis();
        //过期时间
        long exp = now + minutes * 60 * 1000;

        JwtBuilder jwtBuilder = Jwts.builder()
                //签发的算法
                .signWith(SignatureAlgorithm.RS256, privateKey)
                //设置令牌过期时间
                .setExpiration(new Date(exp))
                //设置签发时间
                .setIssuedAt(new Date())
                //设置body数据，自定义设置
                .setClaims(claims);
        return jwtBuilder.compact();
    }

    /**
     * 公钥解析jwt
     *
     * @param jwt jwt字符串
     * @return 返回null证明解析异常
     */
    public static Map<String, Object> parseJwt(String jwt) {
        if (Objects.isNull(publicKey)) {
            publicKey = getPublicKey();
        }

        try {
            return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(jwt).getBody();
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 获取私钥
     *
     * @return 当获取异常时返回null
     */
    private static PrivateKey getPrivateKey() {
        try {
            ClassPathResource keyFileResource = new ClassPathResource(PRIVATE_KEY_PATH);
            //创建秘钥工厂，参数为：秘钥文件、秘钥库密码
            //import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
            //pom文件：
            /*
             公钥私钥生成 https://blog.csdn.net/qq_37470815/article/details/123027798
             <dependency>
             <groupId>org.springframework.security</groupId>
             <artifactId>spring-security-rsa</artifactId>
             <version>1.0.11.RELEASE</version>
             </dependency>
             KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(keyFileResource, "密钥库密码password".toCharArray());
             //获取秘钥，参数为：别名，秘钥密码
             KeyPair keyContent = keyStoreKeyFactory.getKeyPair("alias别名", "秘钥的密码".toCharArray());
             */
            KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(keyFileResource, "dragonwu".toCharArray());
            KeyPair keyContent = keyStoreKeyFactory.getKeyPair("dragonwu", "dragonwu".toCharArray());
            return keyContent.getPrivate();
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 获取公钥
     *
     * @return 当获取异常时返回null
     */
    private static PublicKey getPublicKey() {
        try {
            Resource publicKey = new ClassPathResource(PUBLIC_KEY_PATH);
            InputStreamReader publicKeyIs = new InputStreamReader(publicKey.getInputStream());
            BufferedReader publicKeyBr = new BufferedReader(publicKeyIs);
            StringBuilder publicKeySb = new StringBuilder();
            String line;
            //将文件中的多行变为一行
            while ((line = publicKeyBr.readLine()) != null) {
                publicKeySb.append(line);
            }

            //将String转换成java的PublicKey对象
            byte[] byteKey = Base64.getDecoder().decode(publicKeySb.toString());
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(byteKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(x509EncodedKeySpec);
        } catch (Exception ignored) {
        }
        return null;
    }

    /*
    登录后获取用户信息
     */
    public static OnlineUser getUser() {
        return (OnlineUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

}
